#pragma once
#include <memory>
#include <iostream>
#include <format>

template<size_t N, size_t M, typename T>
struct Matrix {};

template<typename T>
struct Matrix<4, 4, T> {
public:
	Matrix() { memset(value, 0, sizeof(value)); }
	Matrix(T a) { 
		memset(value, 0, sizeof(value));
		for (std::size_t i = 0; i < 4; i++) {
			value[i * 4 + i] = a;
		}
	}
private:
	T value[4 * 4];

public:
	template<typename T>
	friend std::ostream& operator<< (std::ostream& Out, const Matrix<4, 4, T>& Matrix);
};

template<typename T>
std::ostream& operator<< (std::ostream& Out, const Matrix<4, 4, T>& Matrix) {
	Out << std::format("{}, {}, {}, {}\n{}, {}, {}, {}\n{}, {}, {}, {}\n{}, {}, {}, {}",
		Matrix.value[0 * 4 + 0], Matrix.value[0 * 4 + 1], Matrix.value[0 * 4 + 2], Matrix.value[0 * 4 + 3],
		Matrix.value[1 * 4 + 0], Matrix.value[1 * 4 + 1], Matrix.value[1 * 4 + 2], Matrix.value[1 * 4 + 3],
		Matrix.value[2 * 4 + 0], Matrix.value[2 * 4 + 1], Matrix.value[2 * 4 + 2], Matrix.value[2 * 4 + 3],
		Matrix.value[3 * 4 + 0], Matrix.value[3 * 4 + 1], Matrix.value[3 * 4 + 2], Matrix.value[3 * 4 + 3]) << std::endl;
	return Out;
}

using Matrix4x4 = Matrix<4, 4, float>;
